import Guide from '~/components/layout/guide'
import Snippet from '~/components/snippet'
import { InlineCode } from '~/components/text/code'
import { Image } from '~/components/media'
import Caption from '~/components/text/caption'
import Note from '~/components/text/note'
import Link from '~/components/text/link'
import Card from '~/components/card'
import { Code } from '~/components/code'
import DeploySection from '~/components/guides/deploy-section'

export const meta = {
  title: 'Deploy a SendGrid-Powered Contact Form with ZEIT Now',
  description:
    'Create a SendGrid-Powered Next.js and Node.js Contact Form and deploy it with ZEIT Now.',
  name: 'Next.js + Sendgrid',
  type: 'app',
  published: '2019-10-10T17:00:00.000Z',
  authors: ['msweeneydev'],
  url: '/guides/deploying-nextjs-nodejs-and-sendgrid-with-zeit-now',
  image:
    'https://og-image.now.sh/**Deploy%20a%20Next.js%20and%20SendGrid%20App**%20%3Cbr%2F%3E%20with%20ZEIT%20Now.png?theme=light&md=1&fontSize=75px&images=https%3A%2F%2Fassets.zeit.co%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fzeit-black-triangle.svg&images=https%3A%2F%2Fseeklogo.com%2Fimages%2FN%2Fnext-js-logo-7929BCD36F-seeklogo.com.png&images=https%3A%2F%2Fsendgrid.com%2Fwp-content%2Fthemes%2Fsgdotcom%2Fpages%2Fresource%2Fbrand%2F2016%2FSendGrid-Logomark.png&widths=250&widths=auto&widths=300&heights=250&heights=auto&heights=300',
  editUrl:
    'pages/guides/deploying-nextjs-nodejs-and-sendgrid-with-zeit-now.mdx',
  lastEdited: '2020-02-04T12:49:00.000Z'
}

[SendGrid](https://sendgrid.com/) is a cloud-based SMTP provider that allows you to send email without having to maintain email servers.

This guide walks you through creating a [Next.js app](https://nextjs-sendgrid-nodejs.now-examples.now.sh/) with a contact form powered by [SendGrid](https://sendgrid.com/), and how to deploy it with ZEIT Now.

## Step 1: Creating a SendGrid API Key

To start, you need to have [created a SendGrid account](https://signup.sendgrid.com/). Once logged in to SendGrid, follow the setup guide steps for integrating using the Web API, choosing the Node.js option.

You will be asked to supply a name for your API key and given the option to create it.

Once created, make a note of this API key as it will not be shown again, this will be used in the app you create.

<Note>
  On occasion, it can take a few hours for the API key to become active.
</Note>

## Step 2: Creating Your Next.js App

Get started creating your [Next.js](https://nextjs.org) app by making a project directory with the required structure and moving into it:

<Snippet dark text="mkdir -p nextjs-sendgrid/pages/api && cd nextjs-sendgrid" />
<Caption>
  Creating and entering into the <InlineCode>/nextjs-sendgrid</InlineCode>{' '}directory.
</Caption>

Next, [initialize](https://docs.npmjs.com/cli/init) the project:

<Snippet dark text="npm init -y" />
<Caption>
  Initializing the project, this creates a <InlineCode>package.json</InlineCode>{' '}file.
</Caption>

Continue to install [the SendGrid Node.js helper](https://github.com/sendgrid/sendgrid-nodejs) which allows you to send email using your API key, along with the required dependencies for Next.js including `dotenv` for using your API key during local development:

<Snippet dark text="npm i @sendgrid/mail dotenv next react react-dom" />
<Caption>
  Adding the <InlineCode>@sendgrid/mail</InlineCode>, <InlineCode>dotenv</InlineCode>, <InlineCode>next</InlineCode>, <InlineCode>react</InlineCode> and <InlineCode>react-dom</InlineCode> <Link href="https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file">dependencies</Link> to the project.
</Caption>

Inside of the `/pages` directory, create an `index.js` file with the code below:

```jsx
import React, { useState } from 'react'

export default () => {
  const [status, setStatus] = useState({
    submitted: false,
    submitting: false,
    info: { error: false, msg: null }
  })

  const [inputs, setInputs] = useState({
    email: '',
    message: ''
  })

  const handleResponse = (status, msg) => {
    if (status === 200) {
      setStatus({
        submitted: true,
        submitting: false,
        info: { error: false, msg: msg }
      })
      setInputs({
        email: '',
        message: ''
      })
    } else {
      setStatus({
        info: { error: true, msg: msg }
      })
    }
  }

  const handleOnChange = e => {
    e.persist()
    setInputs(prev => ({
      ...prev,
      [e.target.id]: e.target.value
    }))
    setStatus({
      submitted: false,
      submitting: false,
      info: { error: false, msg: null }
    })
  }

  const handleOnSubmit = async e => {
    e.preventDefault()
    setStatus(prevStatus => ({ ...prevStatus, submitting: true }))
    const res = await fetch('/api/send', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(inputs)
    })
    const text = await res.text()
    handleResponse(res.status, text)
  }

  return (
    <main>
      <form onSubmit={handleOnSubmit}>
        <label htmlFor="email">Email</label>
        <input
          id="email"
          type="email"
          onChange={handleOnChange}
          required
          value={inputs.email}
        />
        <label htmlFor="message">Message</label>
        <textarea
          id="message"
          onChange={handleOnChange}
          required
          value={inputs.message}
        />
        <button type="submit" disabled={status.submitting}>
          {!status.submitting
            ? !status.submitted
              ? 'Submit'
              : 'Submitted'
            : 'Submitting...'}
        </button>
      </form>
      {status.info.error && (
        <div className="error">Error: {status.info.msg}</div>
      )}
      {!status.info.error && status.info.msg && (
        <div className="success">{status.info.msg}</div>
      )}
    </main>
  )
}
```

<Caption>
  Adding a <InlineCode>/pages/index.js</InlineCode> file to the project.
</Caption>

Add development and build scripts to the `package.json` file. These allow you to run your app with a development server and tell ZEIT Now how to build your project for deployment:

```json
{
  ...
  "scripts": {
    "dev": "next dev",
    "build": "next build"
  }
}
```

<Caption>
  Adding <InlineCode>dev</InlineCode> and <InlineCode>build</InlineCode> scripts
  to the <InlineCode>package.json</InlineCode> file.
</Caption>

<Note>
  If you wish to use the same styles as the{' '}
  <Link href="https://nextjs-sendgrid-nodejs.now-examples.now.sh/">
    example app
  </Link>
  , you can find them <Link href="https://nextjs-sendgrid-nodejs.now-examples.now.sh/styles/index.css">
    here
  </Link>.
</Note>

## Step 3: Writing the Serverless Function

Create the Node.js API endpoint that will be used to send the form data to the SendGrid API by adding a `send.js` file to the `/pages/api` directory with the following code:

```js
const sgMail = require('@sendgrid/mail')

export default async function(req, res) {
  sgMail.setApiKey(process.env.SENDGRID_API_KEY)

  const { email, message } = req.body

  const content = {
    to: '[your-email-address]',
    from: email,
    subject: `New Message From - ${email}`,
    text: message,
    html: `<p>${message}</p>`
  }

  try {
    await sgMail.send(content)
    res.status(200).send('Message sent successfully.')
  } catch (error) {
    console.log('ERROR', error)
    res.status(400).send('Message not sent.')
  }
}
```

<Caption>
  An example <InlineCode>/pages/api/send.js</InlineCode> file that sends form
  data to the SendGrid API.
</Caption>

<Note>
  Make sure you change the <InlineCode>to</InlineCode> value to the required
  destination for emails sent.
</Note>

Create a `.env` file, adding your SendGrid API key where prompted:

```bash
SENDGRID_API_KEY=[your-sendgrid-api-key]
```

<Caption>
  An example <InlineCode>.env</InlineCode> file that stores environment
  variables for use during local development.
</Caption>

Add a `next.config.js` file that will provide your app with the defined environment variable:

```js
require('dotenv').config()

module.exports = {
  env: {
    SENDGRID_API_KEY: process.env.SENDGRID_API_KEY
  }
}
```

<Caption>
  An example <InlineCode>next.config.js</InlineCode> file that provides
  environment variables to the app.
</Caption>

<Note>
  The app can now be run in development by using{' '}
  <InlineCode>npm run dev</InlineCode>.
</Note>

Create a [Now Secret](/docs/v2/serverless-functions/env-and-secrets/) to securely store the SendGrid API key, this will be used when deploying the app with ZEIT Now.

<Snippet dark text="now secrets add SENDGRID_API_KEY [your-sendgrid-api-key]" />
<Caption>
  Adding the access key as a <strong>Now Secret</strong>.
</Caption>

Lastly, to make the [Now Secret](https://zeit.co/docs/v2/serverless-functions/env-and-secrets/) available to the Serverless Function when deployed, create a `now.json` file:

```json
{
  "build": {
    "env": {
      "SENDGRID_API_KEY": "@sendgrid_api_key"
    }
  }
}
```

<Caption>
  An example <InlineCode>now.json</InlineCode> file that makes a{' '}
  <strong>Now Secret</strong> available to the app.
</Caption>

## Step 4: Deploying the App with ZEIT Now

<DeploySection meta={meta} />

export default ({ children }) => <Guide meta={meta}>{children}</Guide>

export const config = {
  amp: 'hybrid'
}
